﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestLib
{
	/// <summary>
	/// The purpose of this test is to ensure the common activity tracing works as intended.
	/// </summary>
	[TestClass]
	public class TracerTest
	{
		public TracerTest()
		{
			//
			// TODO: Add constructor logic here
			//
		}

		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get
			{
				return testContextInstance;
			}
			set
			{
				testContextInstance = value;
			}
		}

		#region Additional test attributes
		//
		// You can use the following additional attributes as you write your tests:
		//
		// Use ClassInitialize to run code before running the first test in the class
		[ClassInitialize()]
		public static void MyClassInitialize(TestContext testContext)
		{
			CommonLib.Tracer.Start();
		}
		//
		// Use ClassCleanup to run code after all tests in a class have run
		[ClassCleanup()]
		public static void MyClassCleanup()
		{
			CommonLib.Tracer.Stop();
		}
		//
		// Use TestInitialize to run code before running each test 
		// [TestInitialize()]
		// public void MyTestInitialize() { }
		//
		// Use TestCleanup to run code after each test has run
		// [TestCleanup()]
		// public void MyTestCleanup() { }
		//
		#endregion

		[TestMethod]
		public void TestOneThreadNormal()
		{
			// OK, let's do this on one thread:
			CommonLib.Tracer.StartActivity("TestOneThreadNormal");
			CommonLib.Tracer.ReportInformation("1: Message");

			CommonLib.Tracer.StartActivity("TestOneThreadNormalx2");
			CommonLib.Tracer.ReportInformation("2: Message");
			CommonLib.Tracer.ReportInformation("2: Message");
			CommonLib.Tracer.StartActivity("TestOneThreadNormalx3");
			CommonLib.Tracer.ReportInformation("3: Message");
			CommonLib.Tracer.ReportInformation("3: Message");
			CommonLib.Tracer.ReportInformation("3: Message");
			CommonLib.Tracer.StartActivity("TestOneThreadNormalx4");
			CommonLib.Tracer.ReportInformation("4: Message");
			CommonLib.Tracer.EndActivity("TestOneThreadNormalx4");
			CommonLib.Tracer.EndActivity("TestOneThreadNormalx3");
			CommonLib.Tracer.ReportInformation("2: Message");
			CommonLib.Tracer.EndActivity("TestOneThreadNormalx2");
			CommonLib.Tracer.ReportInformation("1: Message");
			CommonLib.Tracer.EndActivity("TestOneThreadNormal");
			// should not cause a crash
			CommonLib.Tracer.EndActivity("TestOneThreadNormal");
		}

		[TestMethod()]
		public void TestOneThreadException()
		{
			try
			{
				CommonLib.Tracer.StartActivity("TestOneThreadNormal");
				CommonLib.Tracer.ReportInformation("1: Message");

				CommonLib.Tracer.StartActivity("TestOneThreadNormalx2");
				CommonLib.Tracer.ReportInformation("2: Message");
				CommonLib.Tracer.ReportInformation("2: Message");
				CommonLib.Tracer.StartActivity("TestOneThreadNormalx3");
				CommonLib.Tracer.ReportInformation("3: Message");
				CommonLib.Tracer.ReportInformation("3: Message");
				CommonLib.Tracer.ReportInformation("3: Message");
				CommonLib.Tracer.StartActivity("TestOneThreadNormalx4");
				CommonLib.Tracer.ReportInformation("4: Message");
				throw new ArgumentException("Bad Argument, man");
				// should not be executed
				//CommonLib.Tracer.StartActivity("TestOneThreadNormalx4");
				//CommonLib.Tracer.EndActivity("TestOneThreadNormalx3");
				//CommonLib.Tracer.ReportInformation("2: Message");
				
			}
			catch (ArgumentException ex)
			{
				CommonLib.Tracer.ReportError("Argument exception", ex);
			}
			finally
			{
				CommonLib.Tracer.EndActivity("TestOneThreadNormalx2");
			}
			CommonLib.Tracer.ReportInformation("1: Message");
			CommonLib.Tracer.EndActivity("TestOneThreadNormal");
		}

		[TestMethod()]
		public void TestAsyncCalls()
		{
			CommonLib.Tracer.StartActivity("TestAsyncCallsx1");

			Random r =new Random();

			for (int i = 0; i < 5; i++)
			{
				CommonLib.Tracer.ReportInformation("Spawning new thread");
				System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(AsyncCall));
				t.Start();
				if (r.Next(2) >= 1)
				{
					System.Threading.Thread.Sleep(100);
				}
			}

			CommonLib.Tracer.EndActivity("TestAsyncCallsx1");
		}

		public void AsyncCall()
		{
			CommonLib.Tracer.StartActivity("NewThread");
			Random r = new Random();
			int a = r.Next(5);
			int i = 0;
			Stack<String> names = new Stack<string>();
			for (; i < a; i++)
			{
				CommonLib.Tracer.StartActivity("ThreadCall" + i);
				names.Push("ThreadCall" + i);
				CommonLib.Tracer.ReportInformation("Thread info" + i);

				if (r.Next(5) < 1)
				{
					// simulate an exception without the overhead;
					CommonLib.Tracer.ReportError("Crazy error!" + i);
					break;
				}
			}
			if (i == a)
			{
				while (names.Count > 0)
				{
					CommonLib.Tracer.EndActivity(names.Pop());
				}
				// only show on good cases
				CommonLib.Tracer.EndActivity("NewThread");
			}
		}
	}
}
